Kerberos.NET
Kerberos.NET copied to clipboard
Server Response for Kerberos Authentication Request
I have written an LDAP server that, among other things, processes Kerberos authentications. I had been using an old C SSPI library to process these authentications, but would like to use Kerberos.NET since we would like to support untrusted domains and use keytab files to support this.
I'm able to authenticate a user using the KerberosAuthenticator.Authenticate(), which is working great. However, I need to send back a response to the client indicating the authentication was successful. For trusted domains, I am able to use the code:
SspiContext serverContext = new SspiContext(mySpn, "Kerberos");
byte[] serverResponse = null;
serverContext.AcceptToken(token, out serverResponse);
And return the contents of serverResponse to the client. I have downloaded the Kerberos.NET source and have tried exposing the KrbApRep object created in the KerberosIdentity constructor among a few other objects, as well as changing the encoding to BER since that's what we need, but am unable to generate the necessary response token.
Any thoughts or pointers would be much appreciated.
The response is always an AP-REP, which is exposed through KerberosIdentity.ApRep
. It's base64 and can be decoded into bytes. Or if you want it directly identity.KrbApReq.CreateResponseMessage() [.EncodeApplication()];
.
If this is null, then the client hasn't requested Mutual Authentication and it shouldn't return an AP-REP.
Kerberos never uses BER. It's always DER. No library will understand it as BER.
Thanks, that was very helpful, as Wireshark is now showing good values for the responseToken. While the network trace now looks correct, the client is still getting an 82 (local error) when sending back the response from Kerberos.NET (using DER encoding as you suggested). I have attached the network traces from the failing and successful attempts. The main difference I can see is that the cipher is shorter (61 bytes) in the Kerberos.NET response than in the SSPI response (106 bytes). Below are network trace images, successful trace listed first.
What does error 82 mean? What client is making the request?
LDAP Result code 82 is unfortunately a very generic LDAP error code with description "local error". In the past, with regards to Kerberos failures, I've seen this error code for causes ranging from bad/missing SPNs to network or firewall issues. SPNs are good, because it works when the host/port is running my old SSPI code, or even using the Kerberos.NET SspiContext code. Everything is on the same network here with no firewalls in place, and there are no errors in Kerberos.NET. There are also no Kerberos errors in the Windows System or Security logs.
The client is a simple SDSP program to test Kerberos:
LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier("host:port", false, false);
LdapConnection conn = new LdapConnection(identifier);
conn.SessionOptions.ProtocolVersion = 3;
conn.AuthType = AuthType.Kerberos;
conn.SessionOptions.SecureSocketLayer = false;
conn.Bind();
The encrypted part contains a structure:
EncAPRepPart ::= [APPLICATION 27] SEQUENCE {
ctime [0] KerberosTime,
cusec [1] Microseconds,
subkey [2] EncryptionKey OPTIONAL,
seq-number [3] UInt32 OPTIONAL
}
I'd expect seq-number to be present, though by definition it's optional so it could be missing. The likely difference is the subkey not being present in the response and the client may not like that for unknown reasons. Is this LdapConnection running on Windows, or is it running on another platform? If it's Windows I can offer instructions for collecting traces where I can decode them. If it's not Windows then you'd have to figure it out some other way.
The client and server are both Windows servers. Please let me know what to do to gather the necessary logs, and which server (client, server, or both) that you need them from. Thanks again for your help.
Grab these scripts: https://aka.ms/authscripts
- Extract, elevate powershell prompt
- start-auth.ps1
- klist.exe purge
-
- stop-auth.ps1
You will get an "authlogs" folder. Find the kerberos.etl, zip it, and send it to me. If it's a test domain that you don't care about you can just upload it here, otherwise email it to me: steve.syfuhs@microsoft. It doesn't contain credentials or anything, but it does include names of things used during the protocol exchange.
I did as you requested on the server running the LDAP service and found many iterations of the following entry in the resulting 9mb Kerberos.etl event log file. They occurred before, during and after the Kerberos authentication attempt. There are different event IDs, but they all have the same content with varying GUIDs. I filtered for any Critical/Error/Warn entries, but there were none. Would the whole log file still be helpful?
Log Name:
Source:
Date: 4/25/2024 7:15:29 PM
Event ID: 135
Task Category: None
Level: Information
Keywords: None
User: N/A
Computer: server.host.local
Description:
Unknown( 135): GUID=0810bf51-06aa-3d3e-2a01-3db7614fea11 (No Format Information found).
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="" Guid="{00000000-0000-0000-0000-000000000000}" />
<EventID>135</EventID>
<Version>0</Version>
<Level>0</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x0</Keywords>
<TimeCreated SystemTime="2024-04-25T23:15:29.581621100Z" />
<EventRecordID>1893</EventRecordID>
<Correlation />
<Execution ProcessID="1228" ThreadID="14608" ProcessorID="7" KernelTime="0" UserTime="0" />
<Channel>
</Channel>
<Computer>server.host.local</Computer>
<Security />
</System>
<DebugData>
<SequenceNumber>0</SequenceNumber>
<FlagsName>
</FlagsName>
<LevelName>
</LevelName>
<Component>
</Component>
<SubComponent>
</SubComponent>
<FileLine>135</FileLine>
<Function>
</Function>
<Message>Unknown( 135): GUID=0810bf51-06aa-3d3e-2a01-3db7614fea11 (No Format Information found).</Message>
</DebugData>
</Event>
I should have clarified please run this on the client to see it receiving the response from Kerberos.NET so I can see why the Windows Kerberos code doesn't like it. You won't be able to decode the ETL file. That's why it says <Message>Unknown( 135): GUID=0810bf51-06aa-3d3e-2a01-3db7614fea11 (No Format Information found).</Message>
.
Attached is the zipped kerberos.etl file from the client. Thanks again. Kerberos.zip
It's failing to decrypt the AP-REP. That generally means it picked the wrong key, which is surprising. Instead of using identity.ApRep
, can you try something like this:
var aprep = CreateTestResponseMessage(identity.KrbApReq).EncodeApplication();
public static KrbApRep CreateTestResponseMessage(DecryptedKrbApReq req)
{
var apRepPart = new KrbEncApRepPart
{
CTime = req.Authenticator.CTime,
CuSec = req.Authenticator.CuSec,
SequenceNumber = req.Authenticator.SequenceNumber
};
var apRep = new KrbApRep
{
EncryptedPart = KrbEncryptedData.Encrypt(
apRepPart.EncodeApplication(),
req.Ticket.Key.AsKey(),
KeyUsage.EncApRepPart
)
};
return apRep;
}
The change is in which key is used. Internally Windows is expecting it to use a different key, which seems to contravene the spec. Unclear. If that is the issue I'll have to dig into it a bit more.
Thanks very much! That worked, I now have a server response that my client acknowledges as a successful authentication, which results in an ensuing request. Now, on to figuring out how to decrypt messages.
I've run into some issues with decoding/decrypting ensuing messages. I've tried using the following code:
KrbApReq apReq = KrbApReq.DecodeApplication(message);
DecryptedKrbApReq req = new DecryptedKrbApReq(apReq, MessageType.KRB_AP_REQ);
req.Decrypt(sessionKey);
and am getting various errors depending on which slice of the incoming message I pass it. Mostly, it looks like the tag doesn't match the expected tag during some point of the DecodeApplication call.
I'm not sure if I should be passing the entire message, just the SASL buffer, or just the payload (see attached network capture). I also see that there is a GSSApiToken.Decode(message) function that I have tried as well. It seems I get further with that, but get an "ASN1 corrupted data" error.
You're passing a WRAP message to the library through the AP-REQ decoder. That just won't work structurally. Additionally, this library doesn't support the WRAP functionality because it's...complicated.