Skip to content

Commit f61c048

Browse files
committed
Copy cname from request in order to be spec compliant
1 parent f38e1bb commit f61c048

File tree

6 files changed

+69
-15
lines changed

6 files changed

+69
-15
lines changed

Kerberos.NET/Entities/Krb/KrbKdcRep.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ out MessageType messageType
113113
throw new InvalidOperationException("A service principal key must be provided");
114114
}
115115

116+
if (request.Compatibility.HasFlag(KerberosCompatibilityFlags.IsolateRealmsConsistently))
117+
{
118+
if (request.ClientName == null)
119+
{
120+
throw new InvalidOperationException("Client name must be provided when IsolateRealmsConsistently is set");
121+
}
122+
123+
if (request.ClientRealmName == null)
124+
{
125+
throw new InvalidOperationException("Client realm name must be provided when IsolateRealmsConsistently is set");
126+
}
127+
}
128+
116129
if (request.Compatibility.HasFlag(KerberosCompatibilityFlags.NormalizeRealmsUppercase))
117130
{
118131
request.RealmName = request.RealmName?.ToUpperInvariant();
@@ -196,8 +209,6 @@ private static KrbEncTicketPart CreateEncTicketPart(
196209
KrbEncryptionKey sessionKey
197210
)
198211
{
199-
var cname = CreateCNameForTicket(request);
200-
201212
var flags = request.Flags;
202213

203214
if (request.PreAuthenticationData?.Any(r => r.Type == PaDataType.PA_REQ_ENC_PA_REP) ?? false)
@@ -211,7 +222,7 @@ KrbEncryptionKey sessionKey
211222

212223
var encTicketPart = new KrbEncTicketPart()
213224
{
214-
CName = cname,
225+
CName = request.Compatibility.HasFlag(KerberosCompatibilityFlags.IsolateRealmsConsistently) ? request.ClientName : CreateCNameForTicket(request),
215226
CRealm = request.Compatibility.HasFlag(KerberosCompatibilityFlags.IsolateRealmsConsistently) ? request.ClientRealmName : request.RealmName,
216227
Key = sessionKey,
217228
AuthTime = request.Now,
@@ -237,11 +248,11 @@ private static KrbPrincipalName CreateCNameForTicket(ServiceTicketRequest reques
237248
{
238249
if (string.IsNullOrEmpty(request.SamAccountName))
239250
{
251+
// This is a bug, fixed under the IsolateRealmsConsistently flag.
252+
// Client realm name is not necessarily the same as the (service) realm name
240253
return KrbPrincipalName.FromPrincipal(
241254
request.Principal,
242-
realm: request.Compatibility.HasFlag(KerberosCompatibilityFlags.IsolateRealmsConsistently) ?
243-
request.ClientRealmName :
244-
request.RealmName
255+
realm: request.RealmName
245256
);
246257
}
247258

Kerberos.NET/Entities/Krb/ServiceTicketRequest.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ public struct ServiceTicketRequest : IEquatable<ServiceTicketRequest>
2828
public KerberosKey KdcAuthorizationKey { get; set; }
2929

3030
/// <summary>
31-
/// The realm name for which the requested identity originated
31+
/// The client name (cname) of the identity requesting the ticket
32+
/// </summary>
33+
public KrbPrincipalName ClientName { get; set; }
34+
35+
/// <summary>
36+
/// The client realm (crealm) name of the identity requesting the ticket
3237
/// </summary>
3338
public string ClientRealmName { get; set; }
3439

@@ -179,6 +184,21 @@ public bool Equals(ServiceTicketRequest other)
179184
return false;
180185
}
181186

187+
if (other.ClientName != this.ClientName)
188+
{
189+
return false;
190+
}
191+
192+
if (other.ClientRealmName != this.ClientRealmName)
193+
{
194+
return false;
195+
}
196+
197+
if (other.EncryptedPartEType != this.EncryptedPartEType)
198+
{
199+
return false;
200+
}
201+
182202
if (other.EncryptedPartKey != this.EncryptedPartKey)
183203
{
184204
return false;
@@ -281,6 +301,10 @@ public override int GetHashCode()
281301
{
282302
return EntityHashCode.GetHashCode(
283303
this.Addresses,
304+
this.ClientName,
305+
this.ClientRealmName,
306+
this.Compatibility,
307+
this.EncryptedPartEType,
284308
this.EncryptedPartKey,
285309
this.EndTime,
286310
this.Flags,

Kerberos.NET/Server/KdcAsReqMessageHandler.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ private ReadOnlyMemory<byte> GenerateAsRep(KrbAsReq asReq, PreAuthenticationCont
167167

168168
var rst = new ServiceTicketRequest
169169
{
170+
// RFC 4120 section 3.1.5 Receipt of KRB_AS_REP Message
171+
// "If the reply message type is KRB_AS_REP, then the client verifies that the cname and crealm fields
172+
// in the cleartext portion of the reply match what it requested."
173+
ClientName = asReq.Body.CName,
174+
ClientRealmName = asReq.Body.Realm,
175+
170176
Principal = context.Principal,
171177
EncryptedPartKey = context.EncryptedPartKey,
172178
EncryptedPartEType = context.EncryptedPartEType,

Kerberos.NET/Server/KdcTgsReqMessageHandler.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,19 @@ public override ReadOnlyMemory<byte> ExecuteCore(PreAuthenticationContext contex
265265

266266
var rst = new ServiceTicketRequest
267267
{
268+
// RFC 4120, section 3.3.3 Generation of KRB_TGS_REP Message:
269+
// "By default, the address field, the client's name and realm, the list of transited realms, the time
270+
// of initial authentication, the expiration time, and the authorization data of the newly-issued
271+
// ticket will be copied from the TGT or renewable ticket."
272+
ClientName = context.Ticket.CName,
273+
ClientRealmName = context.Ticket.CRealm,
274+
268275
KdcAuthorizationKey = context.EvidenceTicketKey,
269276
Principal = context.Principal,
270277
EncryptedPartKey = context.EncryptedPartKey,
271278
EncryptedPartEType = context.EncryptedPartEType,
272279
ServicePrincipal = context.ServicePrincipal,
273280
ServicePrincipalKey = serviceKey,
274-
ClientRealmName = context.Ticket.CRealm,
275281
RealmName = tgsReq.Body.Realm,
276282
Addresses = tgsReq.Body.Addresses,
277283
RenewTill = context.Ticket.RenewTill,

Tests/Tests.Kerberos.NET/Client/HttpKerberosTransportTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage reques
9292

9393
var rst = new ServiceTicketRequest
9494
{
95+
ClientName = KrbPrincipalName.FromPrincipal(principal),
96+
ClientRealmName = Realm,
9597
Principal = principal,
9698
EncryptedPartKey = principalKey,
9799
ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96)

Tests/Tests.Kerberos.NET/Messages/KrbKdcRepTests.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,27 @@ public void CreateServiceTicket()
7676

7777
var tgsRep = KrbKdcRep.GenerateServiceTicket<KrbTgsRep>(new ServiceTicketRequest
7878
{
79-
EncryptedPartKey = key,
79+
ClientName = KrbPrincipalName.FromString("blah@test.com"),
80+
ClientRealmName = "test.com",
81+
Principal = new FakeKerberosPrincipal("blah@test.com"),
82+
8083
ServicePrincipal = new FakeKerberosPrincipal("blah@blah.com"),
8184
ServicePrincipalKey = key,
82-
Principal = new FakeKerberosPrincipal("blah@blah2.com"),
8385
RealmName = "blah.com",
84-
ClientRealmName = "test.com",
86+
87+
EncryptedPartKey = key,
8588
Compatibility = KerberosCompatibilityFlags.IsolateRealmsConsistently,
8689
});
8790

8891
Assert.IsNotNull(tgsRep);
8992
Assert.AreEqual("blah.com", tgsRep.Ticket.Realm);
9093
Assert.AreEqual("blah@blah.com/blah.com", tgsRep.Ticket.SName.FullyQualifiedName);
9194
Assert.AreEqual("test.com", tgsRep.CRealm);
92-
Assert.AreEqual("blah@blah2.com", tgsRep.CName.FullyQualifiedName);
95+
Assert.AreEqual("blah@test.com", tgsRep.CName.FullyQualifiedName);
9396

9497
var ticketEncPart = tgsRep.Ticket.EncryptedPart.Decrypt(key, KeyUsage.Ticket, KrbEncTicketPart.DecodeApplication);
9598
Assert.AreEqual("test.com", ticketEncPart.CRealm);
96-
Assert.AreEqual("blah@blah2.com", ticketEncPart.CName.FullyQualifiedName);
99+
Assert.AreEqual("blah@test.com", ticketEncPart.CName.FullyQualifiedName);
97100
}
98101

99102
[TestMethod]
@@ -121,12 +124,14 @@ string expectedCRealm
121124

122125
var tgsRep = KrbKdcRep.GenerateServiceTicket<KrbTgsRep>(new ServiceTicketRequest
123126
{
127+
Principal = new FakeKerberosPrincipal($"blah@{crealm}"),
128+
ClientName = KrbPrincipalName.FromString($"blah@{crealm}"),
129+
ClientRealmName = crealm,
130+
124131
EncryptedPartKey = key,
125132
ServicePrincipal = new FakeKerberosPrincipal("blah@blah.com"),
126133
ServicePrincipalKey = key,
127-
Principal = new FakeKerberosPrincipal("blah@blah2.com"),
128134
RealmName = realm,
129-
ClientRealmName = crealm,
130135
Compatibility = compatibilityFlags,
131136
});
132137

0 commit comments

Comments
 (0)