Skip to content

KRB5_NT_MS_PRINCIPAL returned in S4U2Self reply when using PA-S4U-X509-USER, causing IndexOutOfRangeException #431

Description

@Vladislav52

Describe the bug
When using the S4U2Self flow with a user certificate via the PA-S4U-X509-USER padata type, the Windows KDC returns the client name (cname) with the Microsoft-specific name type KRB5_NT_MS_PRINCIPAL (-128) instead of the expected NT-ENTERPRISE (10) or another standard type. This behavior causes Kerberos.NET to throw an IndexOutOfRangeException when attempting to access FullyQualifiedName property.

To Reproduce

  1. Configure a service account with a certificate supporting PKINIT.

  2. Obtain a user certificate containing the user's UPN in the SAN (Subject Alternative Name) field:

    Other Name: Principal Name=testuser@domain.local

    RFC822 Name=testuser@try.domain.com

  3. Authenticate the service account using KerberosAsymmetricCredential.

  4. Perform an S4U2Self request using RequestServiceTicket:

var selfApReq = await client.GetServiceTicket(
    new RequestServiceTicket
    {
        ServicePrincipalName = ServiceSpn,
        S4uTarget = fullUpn,
        S4uTargetCertificate = publicCert,
        ApOptions = ApOptions.MutualRequired,
    }
);
  1. Result of the request:
`TGS-REQ`
cname
    name-type: kRB5-NT-ENTERPRISE-PRINCIPAL (10)
    name-string: 1 item
        KerberosString: testuser@domain.local
`TGS-REP`
  cname
          name-type: kRB5-NT-MS-PRINCIPAL (-128)
          cname-string: 1 item
              CNameString: testuser   
  ticket
          tkt-vno: 5
          realm: DOMAIN.LOCAL
          sname
              name-type: kRB5-NT-SRV-INST (2)
              sname-string: 2 items
                  SNameString: HTTP
                  SNameString: host.domain.local
          enc-part
      enc-part
`StackTrace:`
{"Index was outside the bounds of the array."}
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146233080
    HelpLink: null
    InnerException: null
    Message: "Index was outside the bounds of the array."
    Source: "Kerberos.NET"
    StackTrace: 
	   at Kerberos.NET.Entities.KrbPrincipalName.MakeFullName(IEnumerable`1 names, PrincipalNameType type, Boolean normalizeAlias)
   at Kerberos.NET.Client.KerberosClient.<RequestTgs>d__101.MoveNext()
   at Kerberos.NET.Client.KerberosClient.<RequestDecryptedTgs>d__86.MoveNext()
   at Kerberos.NET.Client.KerberosClient.<GetServiceTicket>d__84.MoveNext()
  1. The library attempts to access FullyQualifiedName on the returned CName, which throws an IndexOutOfRangeException because the principal name lacks the expected realm/domain component. The error occurs specifically in the following logging line within KerberosClient.RequestTgs:
this.logger.LogInformation(
    "TGS-REP for {SPN}; CName = {CName}; CRealm = {CRealm}; PAData = {PADataTypes}",
    tgsRep.Ticket.SName.FullyQualifiedName,
    tgsRep.CName.FullyQualifiedName,  // ← IndexOutOfRangeException here
    tgsRep.CRealm,
    tgsRep.PaData?.Select(s => s.Type)?.ToArray()
);

Temporary Workaround:&

Commenting out the logging line that accesses tgsRep.CName.FullyQualifiedName temporarily resolves the issue:

//this.logger.LogInformation(
//    "TGS-REP for {SPN}; CName = {CName}; CRealm = {CRealm}; PAData = {PADataTypes}",
//    tgsRep.Ticket.SName.FullyQualifiedName,
//    tgsRep.CName.FullyQualifiedName,
//    tgsRep.CRealm,
//    tgsRep.PaData?.Select(s => s.Type)?.ToArray()
//);`

However, this only bypasses the logging issue; the underlying problem of handling KRB5_NT_MS_PRINCIPAL remains.

Expected behavior
The library should handle the KRB5_NT_MS_PRINCIPAL name type robustly:

  1. Implement safe parsing of PrincipalType so that the entire flow does not break when encountering Microsoft-specific name types.

  2. FullyQualifiedName construction: When KRB5_NT_MS_PRINCIPAL is encountered, the library should:

     - If the principal name contains an '@' character, use it as-is (treat it like NT-ENTERPRISE).
    
     - If the principal name does NOT contain '@' (e.g., userName), attempt to construct the fully qualified name using the realm information from the ticket response (CRealm or Ticket.Realm), similar to how NT-ENTERPRISE names are handled.
    
  3. Logging: The logging code should gracefully handle cases where CName might be incomplete or have a non-standard type, perhaps by:

     - Checking CName and Name array length before accessing FullyQualifiedName, or
    
     - Using a safe accessor method that handles edge cases.
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions