private EncTicketPart RetrieveAndDecryptServiceTicket(KerberosFunctionalClient kerberosClient, out EncryptionKey serviceKey) { //Create and send AS request const KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE; kerberosClient.SendAsRequest(options, null); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client expects Kerberos Error from KDC"); //Receive preauthentication required error METHOD_DATA methodData; KerberosKrbError krbError = kerberosClient.ExpectPreauthRequiredError(out methodData); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client sends AS request with PA-DATA set"); //Create sequence of PA data string timeStamp = KerberosUtility.CurrentKerberosTime.Value; PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, kerberosClient.Context.SelectedEType, kerberosClient.Context.CName.Password, kerberosClient.Context.CName.Salt); PaPacRequest paPacRequest = new PaPacRequest(true); Asn1SequenceOf <PA_DATA> seqOfPaData = new Asn1SequenceOf <PA_DATA>(new[] { paEncTimeStamp.Data, paPacRequest.Data }); //Create and send AS request kerberosClient.SendAsRequest(options, seqOfPaData); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client expects AS response from KDC"); KerberosAsResponse asResponse = kerberosClient.ExpectAsResponse(); BaseTestSite.Assert.IsNotNull(asResponse.Response.ticket, "AS response should contain a TGT."); //Create and send TGS request BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client sends TGS request to KDC"); kerberosClient.SendTgsRequest(servicePrincipalName, options); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client expects TGS response from KDC"); KerberosTgsResponse tgsResponse = kerberosClient.ExpectTgsResponse(); BaseTestSite.Assert.AreEqual(servicePrincipalName, KerberosUtility.PrincipalName2String(tgsResponse.Response.ticket.sname), "Service principal name in service ticket should match expected."); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Decrypt SMB2 Service Ticket"); serviceKey = keyManager.QueryKey(servicePrincipalName, TestConfig.DomainName, kerberosClient.Context.SelectedEType); tgsResponse.DecryptTicket(serviceKey); return(tgsResponse.TicketEncPart); }
private void CrossRealm_Smb2_AccessFile(string localRealmName, string trustuedRealmName, User localUser, Computer localKDC, Computer trustedKDC, TransportType transportType, FileServer fileserverInTrustedRealm, string filePath, string fileName, bool expectAccessDeny) { base.Logging(); client = new KerberosTestClient(localRealmName, localUser.Username, localUser.Password, KerberosAccountType.User, localKDC.IPAddress, localKDC.Port, transportType, testConfig.SupportedOid); //Create and send AS request KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE; client.SendAsRequest(options, null); //Recieve preauthentication required error METHOD_DATA methodData; KerberosKrbError krbError = client.ExpectPreauthRequiredError(out methodData); //Create sequence of PA data string timeStamp = KerberosUtility.CurrentKerberosTime.Value; PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, this.client.Context.SelectedEType, this.client.Context.CName.Password, this.client.Context.CName.Salt); PaPacRequest paPacRequest = new PaPacRequest(true); Asn1SequenceOf <PA_DATA> seqOfPaData = new Asn1SequenceOf <PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data }); //Create and send AS request client.SendAsRequest(options, seqOfPaData); KerberosAsResponse asResponse = client.ExpectAsResponse(); //Create and send TGS request if (this.testConfig.TrustType == Adapter.TrustType.Forest) { client.SendTgsRequest(fileserverInTrustedRealm.Smb2ServiceName, options); } else if (this.testConfig.TrustType == Adapter.TrustType.Realm) { client.SendTgsRequest(trustedKDC.DefaultServiceName, options); } BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send TGS request"); KerberosTgsResponse tgsResponse = client.ExpectTgsResponse(); BaseTestSite.Log.Add(LogEntryKind.Comment, "Receive a referral TGS response."); BaseTestSite.Assert.AreEqual(trustedKDC.DefaultServiceName, KerberosUtility.PrincipalName2String(tgsResponse.Response.ticket.sname), "The service principal name in referral ticket should match expected."); BaseTestSite.Assert.AreEqual(localRealmName.ToLower(), tgsResponse.Response.ticket.realm.Value.ToLower(), "The realm name in referral ticket should match expected."); //Change realm client.ChangeRealm(trustuedRealmName, trustedKDC.IPAddress, trustedKDC.Port, this.testConfig.TransportType); //Create and send referral TGS request client.SendTgsRequest(fileserverInTrustedRealm.Smb2ServiceName, options); KerberosTgsResponse refTgsResponse = client.ExpectTgsResponse(); BaseTestSite.Assert.AreEqual(fileserverInTrustedRealm.Smb2ServiceName, KerberosUtility.PrincipalName2String(refTgsResponse.Response.ticket.sname), "The service principal name in service ticket should match expected."); BaseTestSite.Assert.AreEqual(trustuedRealmName.ToLower(), refTgsResponse.Response.ticket.realm.Value.ToLower(), "The realm name in service ticket should match expected."); EncryptionKey key = testConfig.QueryKey(fileserverInTrustedRealm.Smb2ServiceName, client.Context.Realm.ToString(), client.Context.SelectedEType); refTgsResponse.DecryptTicket(key); BaseTestSite.Assert.AreEqual(localRealmName.ToLower(), refTgsResponse.TicketEncPart.crealm.Value.ToLower(), "Realm name in service ticket encrypted part should match expected."); BaseTestSite.Assert.AreEqual(localUser.Username.ToLower(), KerberosUtility.PrincipalName2String(refTgsResponse.TicketEncPart.cname).ToLower(), "User name in service ticket encrypted part should match expected."); AuthorizationData data = null; EncryptionKey subkey = KerberosUtility.GenerateKey(client.Context.SessionKey); byte[] token = client.CreateGssApiToken(ApOptions.MutualRequired, data, subkey, ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG); BaseTestSite.Log.Add(LogEntryKind.Comment, "Logon to fileserver and Access File."); AccessFile(filePath, fileName, fileserverInTrustedRealm, token, refTgsResponse.EncPart.key, expectAccessDeny); }
private void DAC_Smb2_AccessFile(string RealmName, User user, Computer kdc, TransportType transportType, FileServer fileserver, string filePath, string fileName, bool expectAccessDeny) { base.Logging(); client = new KerberosTestClient(RealmName, user.Username, user.Password, KerberosAccountType.User, kdc.IPAddress, kdc.Port, transportType, testConfig.SupportedOid); //Create and send AS request KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE; client.SendAsRequest(options, null); //Recieve preauthentication required error METHOD_DATA methodData; KerberosKrbError krbError = client.ExpectPreauthRequiredError(out methodData); //Create sequence of PA data string timeStamp = KerberosUtility.CurrentKerberosTime.Value; PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, client.Context.SelectedEType, this.client.Context.CName.Password, this.client.Context.CName.Salt); PaPacRequest paPacRequest = new PaPacRequest(true); Asn1SequenceOf <PA_DATA> seqOfPaData = new Asn1SequenceOf <PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data }); //Create and send AS request client.SendAsRequest(options, seqOfPaData); KerberosAsResponse asResponse = client.ExpectAsResponse(); BaseTestSite.Assert.IsNotNull(asResponse.Response.ticket, "AS response should contain a TGT."); //Create and send TGS request client.SendTgsRequest(fileserver.Smb2ServiceName, options); KerberosTgsResponse tgsResponse = client.ExpectTgsResponse(); BaseTestSite.Assert.AreEqual(fileserver.Smb2ServiceName, KerberosUtility.PrincipalName2String(tgsResponse.Response.ticket.sname), "Service principal name in service ticket should match expected."); EncryptionKey key = testConfig.QueryKey(fileserver.Smb2ServiceName, client.Context.Realm.ToString(), client.Context.SelectedEType); tgsResponse.DecryptTicket(key); BaseTestSite.Assert.AreEqual(RealmName.ToLower(), tgsResponse.TicketEncPart.crealm.Value.ToLower(), "Realm name in service ticket encrypted part should match expected."); BaseTestSite.Assert.AreEqual(user.Username.ToLower(), KerberosUtility.PrincipalName2String(tgsResponse.TicketEncPart.cname).ToLower(), "User name in service ticket encrypted part should match expected."); //Assert authorization data if (this.testConfig.IsKileImplemented) { BaseTestSite.Assert.IsNotNull(tgsResponse.TicketEncPart.authorization_data, "The ticket contains Authorization data."); AdWin2KPac adWin2kPac = FindOneInAuthData <AdWin2KPac>(tgsResponse.TicketEncPart.authorization_data.Elements); BaseTestSite.Assert.IsNotNull(adWin2kPac, "The Authorization data contains AdWin2KPac."); } AuthorizationData data = null; EncryptionKey subkey = KerberosUtility.GenerateKey(client.Context.SessionKey); byte[] token = client.CreateGssApiToken(ApOptions.MutualRequired, data, subkey, ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG); BaseTestSite.Log.Add(LogEntryKind.Comment, "Logon to fileserver and Access File."); AccessFile(filePath, fileName, fileserver, token, tgsResponse.EncPart.key, expectAccessDeny); }
private void claimsTest_Kerberos_CrossRealm_ADSource_User_Only(bool ctaFromConfig) { client = new KerberosTestClient(this.testConfig.LocalRealm.RealmName, this.testConfig.LocalRealm.User[2].Username, this.testConfig.LocalRealm.User[2].Password, KerberosAccountType.User, testConfig.LocalRealm.KDC[0].IPAddress, testConfig.LocalRealm.KDC[0].Port, testConfig.TransportType, testConfig.SupportedOid); //Create and send AS request KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE; client.SendAsRequest(options, null); //Recieve preauthentication required error METHOD_DATA methodData; KerberosKrbError krbError = client.ExpectPreauthRequiredError(out methodData); //Create sequence of PA data string timeStamp = KerberosUtility.CurrentKerberosTime.Value; PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, this.client.Context.SelectedEType, this.client.Context.CName.Password, this.client.Context.CName.Salt); PaPacRequest paPacRequest = new PaPacRequest(true); PaPacOptions paPacOptions = new PaPacOptions(PacOptions.Claims | PacOptions.ForwardToFullDc); Asn1SequenceOf <PA_DATA> seqOfPaData = new Asn1SequenceOf <PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data, paPacOptions.Data }); //Create and send AS request client.SendAsRequest(options, seqOfPaData); KerberosAsResponse asResponse = client.ExpectAsResponse(); Asn1SequenceOf <PA_DATA> seqOfPaData2 = new Asn1SequenceOf <PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data }); //Create and send TGS request client.SendTgsRequest(this.testConfig.TrustedRealm.KDC[0].DefaultServiceName, options, seqOfPaData2); BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send TGS request"); KerberosTgsResponse tgsResponse = client.ExpectTgsResponse(); BaseTestSite.Log.Add(LogEntryKind.Comment, "Receive a referral TGS response."); BaseTestSite.Assert.AreEqual(this.testConfig.TrustedRealm.KDC[0].DefaultServiceName, KerberosUtility.PrincipalName2String(tgsResponse.Response.ticket.sname), "The service principal name in referral ticket should match expected."); BaseTestSite.Assert.AreEqual(this.testConfig.LocalRealm.RealmName.ToLower(), tgsResponse.Response.ticket.realm.Value.ToLower(), "The realm name in referral ticket should match expected."); EncryptionKey key = testConfig.QueryKey(this.testConfig.TrustedRealm.KDC[0].DefaultServiceName + "@" + this.testConfig.LocalRealm.RealmName, client.Context.Realm.ToString(), client.Context.SelectedEType); tgsResponse.DecryptTicket(key); CLAIMS_SET claims = new CLAIMS_SET(); AdWin2KPac adWin2kPac = FindOneInAuthData <AdWin2KPac>(tgsResponse.TicketEncPart.authorization_data.Elements); bool foundClaims = false; foreach (PacInfoBuffer buf in adWin2kPac.Pac.PacInfoBuffers) { if (buf.GetType() == typeof(ClientClaimsInfo)) { claims = ((ClientClaimsInfo)buf).NativeClaimSet; foundClaims = true; } } BaseTestSite.Assert.IsTrue(foundClaims, "Found claims in referral TGS Ticket"); foundClaims = false; #region genertaed transformed claims Dictionary <string, string> expectedClaims = new Dictionary <string, string>(); if (!ctaFromConfig) { ClaimTransformer transformer = new ClaimTransformer(this.testConfig.TrustedRealm.KDC[0].IPAddress, this.testConfig.TrustedRealm.RealmName, this.testConfig.TrustedRealm.Admin.Username, this.testConfig.TrustedRealm.Admin.Password); List <CLAIMS_ARRAY> transformed = null; BaseTestSite.Assert.AreEqual <Win32ErrorCode_32>(Win32ErrorCode_32.ERROR_SUCCESS, transformer.TransformClaimsOnTrustTraversal(claims.ClaimsArrays, this.testConfig.LocalRealm.RealmName, true, out transformed), "should successfully transform claims"); foreach (CLAIMS_ARRAY array in transformed) { foreach (CLAIM_ENTRY entry in array.ClaimEntries) { string id = entry.Id; string value = null; switch (entry.Type) { case CLAIM_TYPE.CLAIM_TYPE_BOOLEAN: value = entry.Values.Struct4.BooleanValues[0].ToString(); break; case CLAIM_TYPE.CLAIM_TYPE_INT64: value = entry.Values.Struct1.Int64Values[0].ToString(); break; case CLAIM_TYPE.CLAIM_TYPE_STRING: value = entry.Values.Struct3.StringValues[0].ToString(); break; case CLAIM_TYPE.CLAIM_TYPE_UINT64: value = entry.Values.Struct2.Uint64Values[0].ToString(); break; default: BaseTestSite.Assert.Fail("Found invalid claim type during transform, value:" + (int)entry.Type); break; } expectedClaims.Add(id.ToLower(), value.ToLower()); } } } else { string[] tmp = this.testConfig.LocalRealm.User[2].TransformedClaims.ToLower().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries); BaseTestSite.Assert.IsTrue(tmp != null && tmp.Length % 2 == 0, "Claim.Crossforest.TransformedClaims in PTFConfig should be valid and not empty"); for (int i = 0; i < tmp.Length; i += 2) { expectedClaims.Add(tmp[i], tmp[i + 1]); } } #endregion //Change realm client.ChangeRealm(this.testConfig.TrustedRealm.RealmName, this.testConfig.TrustedRealm.KDC[0].IPAddress, this.testConfig.TrustedRealm.KDC[0].Port, this.testConfig.TransportType); //Create and send referal TGS request client.SendTgsRequest(this.testConfig.TrustedRealm.FileServer[0].Smb2ServiceName, options); KerberosTgsResponse refTgsResponse = client.ExpectTgsResponse(); BaseTestSite.Assert.AreEqual(this.testConfig.TrustedRealm.FileServer[0].Smb2ServiceName, KerberosUtility.PrincipalName2String(refTgsResponse.Response.ticket.sname), "The service principal name in service ticket should match expected."); BaseTestSite.Assert.AreEqual(this.testConfig.TrustedRealm.RealmName.ToLower(), refTgsResponse.Response.ticket.realm.Value.ToLower(), "The realm name in service ticket should match expected."); key = testConfig.QueryKey(this.testConfig.TrustedRealm.FileServer[0].Smb2ServiceName, client.Context.Realm.ToString(), client.Context.SelectedEType); refTgsResponse.DecryptTicket(key); BaseTestSite.Assert.AreEqual(this.testConfig.LocalRealm.RealmName.ToLower(), refTgsResponse.TicketEncPart.crealm.Value.ToLower(), "Realm name in service ticket encrypted part should match expected."); BaseTestSite.Assert.AreEqual(this.testConfig.LocalRealm.User[2].Username, KerberosUtility.PrincipalName2String(refTgsResponse.TicketEncPart.cname).ToLower(), "User name in service ticket encrypted part should match expected."); adWin2kPac = FindOneInAuthData <AdWin2KPac>(refTgsResponse.TicketEncPart.authorization_data.Elements); foreach (PacInfoBuffer buf in adWin2kPac.Pac.PacInfoBuffers) { if (buf.GetType() == typeof(ClientClaimsInfo)) { foundClaims = true; claims = ((ClientClaimsInfo)buf).NativeClaimSet; } } int errors = 0; BaseTestSite.Assert.IsTrue(foundClaims, "Found claims in reference TGS Ticket"); for (int i = 0; i < claims.ClaimsArrays[0].ClaimEntries.Length; i++) { string claimvalue = null; if (!expectedClaims.TryGetValue(claims.ClaimsArrays[0].ClaimEntries[i].Id.ToLower(), out claimvalue)) { errors++; BaseTestSite.Log.Add(LogEntryKind.CheckFailed, "Found unexpected claim with id: " + claims.ClaimsArrays[0].ClaimEntries[i].Id + " after transform"); } else { if (claimvalue != claims.ClaimsArrays[0].ClaimEntries[i].Values.Struct3.StringValues[0].ToLower()) { errors++; BaseTestSite.Log.Add( LogEntryKind.CheckFailed, "Value of claim \"" + claims.ClaimsArrays[0].ClaimEntries[i].Id + "\" is not expected, expected: " + claimvalue + " ,actual: " + claims.ClaimsArrays[0].ClaimEntries[i].Values.Struct3.StringValues[0]); } expectedClaims.Remove(claims.ClaimsArrays[0].ClaimEntries[i].Id); } } BaseTestSite.Assert.AreEqual(expectedClaims.Count, claims.ClaimsArrays[0].ClaimEntries.Count(), "Claims count should be equal."); BaseTestSite.Assert.AreEqual <int>(0, errors, "Expect no error should be found when compare claims from reference TGS ticket"); }
private void Smb2KerberosAuthentication(CaseVariant variant) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Initialize Kerberos Functional Client"); KerberosFunctionalClient kerberosClient = new KerberosFunctionalClient( TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, KerberosAccountType.User, KDCIP, KDCPort, TransportType.TCP, OidPkt, BaseTestSite); #region Service Ticket EncryptionKey serviceKey; EncTicketPart encTicketPart = RetrieveAndDecryptServiceTicket(kerberosClient, out serviceKey); Ticket serviceTicket = kerberosClient.Context.Ticket.Ticket; Realm crealm = serviceTicket.realm; BaseTestSite.Assert.AreEqual(TestConfig.DomainName.ToLower(), encTicketPart.crealm.Value.ToLower(), "Realm name in service ticket encrypted part should match as expected, case insensitive"); BaseTestSite.Assert.AreEqual(TestConfig.UserName.ToLower(), KerberosUtility.PrincipalName2String(encTicketPart.cname).ToLower(), "User name in service ticket encrypted part should match as expected, case insensitive."); if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_TKT)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Add a type-unknown AuthorizationData to the ticket"); AuthorizationDataElement unknownElement = GenerateUnKnownAuthorizationDataElement(); AppendNewAuthDataElement(encTicketPart.authorization_data, unknownElement); } if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_TKT_OPTIONAL)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Add a type-unknown AuthorizationData which is inside AD_IF_RELEVANT to the ticket"); AuthorizationDataElement unknownElement = GenerateUnKnownAuthorizationDataElement(); AD_IF_RELEVANT ifRelavantElement = new AD_IF_RELEVANT(new[] { unknownElement }); var dataBuffer = new Asn1BerEncodingBuffer(); ifRelavantElement.BerEncode(dataBuffer); AuthorizationDataElement unknownElementOptional = new AuthorizationDataElement(new KerbInt32((long)AuthorizationData_elementType.AD_IF_RELEVANT), new Asn1OctetString(dataBuffer.Data)); AppendNewAuthDataElement(encTicketPart.authorization_data, unknownElementOptional); } if (variant.HasFlag(CaseVariant.TICKET_NOT_VALID)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Change the Ticket start time to tomorrow"); DateTime tomorrow = DateTime.Now.AddDays(1); string kerbTimeString = tomorrow.ToUniversalTime().ToString("yyyyMMddhhmmssZ"); encTicketPart.starttime = new KerberosTime(kerbTimeString, true); } if (variant.HasFlag(CaseVariant.TICKET_EXPIRED)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Change the Ticket end time to yesterday"); DateTime yesterday = DateTime.Now.AddDays(-1); string kerbTimeString = yesterday.ToUniversalTime().ToString("yyyyMMddhhmmssZ"); encTicketPart.endtime = new KerberosTime(kerbTimeString, true); } if (variant.HasFlag(CaseVariant.TICKET_WRONG_ENC_KEY)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Modify the Ticket, making it encrypted with wrong key"); serviceKey = KerberosUtility.GenerateKey(serviceKey); } EncryptedData data = EncryptTicket(encTicketPart, serviceKey); serviceTicket.enc_part = data; if (variant.HasFlag(CaseVariant.TICKET_WRONG_REALM)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Change the Realm in the Ticket to an unknown realm"); serviceTicket.realm = new Realm("kerb.com"); } if (variant.HasFlag(CaseVariant.TICKET_WRONG_SNAME)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Change the SNAME in the Ticket to an unknown service name"); serviceTicket.sname = new PrincipalName(new KerbInt32((long)PrincipalType.NT_SRV_INST), KerberosUtility.String2SeqKerbString("UnknownService", TestConfig.DomainName)); } if (variant.HasFlag(CaseVariant.TICKET_WRONG_KVNO)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Change the KVNO in the Ticket to an invalid Key Version Number (Int32.MaxValue)"); const int invalidKvno = System.Int32.MaxValue; serviceTicket.enc_part.kvno = new KerbInt32(invalidKvno); } #endregion #region Authenticator BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create Authenticator"); EncryptionKey subkey = KerberosUtility.GenerateKey(kerberosClient.Context.SessionKey); PrincipalName cname; if (variant.HasFlag(CaseVariant.AUTHENTICATOR_CNAME_NOT_MATCH)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Use wrong cname in the Authenticator"); cname = new PrincipalName(new KerbInt32((long)PrincipalType.NT_PRINCIPAL), KerberosUtility.String2SeqKerbString(TestConfig.NonAdminUserName, TestConfig.DomainName)); } else { cname = kerberosClient.Context.CName.Name; } Authenticator authenticator = CreateAuthenticator(cname, crealm, subkey); if (variant.HasFlag(CaseVariant.AUTHENTICATOR_CREALM_NOT_MATCH)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Use wrong crealm in the Authenticator"); authenticator.crealm = new Realm("kerb.com"); } if (variant.HasFlag(CaseVariant.AUTHENTICATOR_EXCEED_TIME_SKEW)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Change the ctime in the Authenticator to one hour later"); DateTime oneHourLater = DateTime.Now.AddHours(1); string kerbTimeString = oneHourLater.ToUniversalTime().ToString("yyyyMMddhhmmssZ"); authenticator.ctime = new KerberosTime(kerbTimeString, true); } if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_AUTHENTICATOR)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Add a type-unknown AuthorizationData to the Authenticator"); AuthorizationDataElement unknownElement = GenerateUnKnownAuthorizationDataElement(); authenticator.authorization_data = new AuthorizationData(new[] { unknownElement }); } if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_AUTHENTICATOR_OPTIONAL)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Add a type-unknown AuthorizationData which is inside AD_IF_RELEVANT to the Authenticator"); AuthorizationDataElement unknownElement = GenerateUnKnownAuthorizationDataElement(); AD_IF_RELEVANT ifRelavantElement = new AD_IF_RELEVANT(new[] { unknownElement }); var dataBuffer = new Asn1BerEncodingBuffer(); ifRelavantElement.BerEncode(dataBuffer); AuthorizationDataElement unknownElementOptional = new AuthorizationDataElement(new KerbInt32((long)AuthorizationData_elementType.AD_IF_RELEVANT), new Asn1OctetString(dataBuffer.Data)); authenticator.authorization_data = new AuthorizationData(new[] { unknownElementOptional }); } #endregion #region AP Request BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create AP Request"); if (variant.HasFlag(CaseVariant.AUTHENTICATOR_WRONG_ENC_KEY)) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Use wrong key to encrypt the Authenticator"); kerberosClient.Context.Ticket.SessionKey = KerberosUtility.GenerateKey(kerberosClient.Context.Ticket.SessionKey); } KerberosApRequest request = new KerberosApRequest( kerberosClient.Context.Pvno, new APOptions(KerberosUtility.ConvertInt2Flags((int)ApOptions.MutualRequired)), kerberosClient.Context.Ticket, authenticator, KeyUsageNumber.AP_REQ_Authenticator ); #endregion BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create GSS Token"); byte[] token = KerberosUtility.AddGssApiTokenHeader(request, OidPkt, GssToken); Smb2FunctionalClientForKerbAuth smb2Client = new Smb2FunctionalClientForKerbAuth(TestConfig.Timeout, TestConfig, BaseTestSite); smb2Client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); #region Check the result byte[] repToken; uint status = DoSessionSetupWithGssToken(smb2Client, token, out repToken); if (variant.HasFlag(CaseVariant.AUTHENTICATOR_CNAME_NOT_MATCH) || variant.HasFlag(CaseVariant.AUTHENTICATOR_CREALM_NOT_MATCH)) { BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because the cname or crealm in the authenticator does not match the same field in the Ticket"); if (TestConfig.IsWindowsPlatform) { KerberosKrbError krbError = kerberosClient.GetKrbErrorFromToken(repToken); BaseTestSite.Assert.AreEqual(KRB_ERROR_CODE.KRB_AP_ERR_BADMATCH, krbError.ErrorCode, "SMB Server should return {0}", KRB_ERROR_CODE.KRB_AP_ERR_BADMATCH); } smb2Client.Disconnect(); return; } if (variant.HasFlag(CaseVariant.AUTHENTICATOR_WRONG_ENC_KEY) || variant.HasFlag(CaseVariant.TICKET_WRONG_ENC_KEY)) { BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because Ticket or Authenticator cannot be correctly decrypted"); if (TestConfig.IsWindowsPlatform) { KerberosKrbError krbError = kerberosClient.GetKrbErrorFromToken(repToken); BaseTestSite.Assert.AreEqual(KRB_ERROR_CODE.KRB_AP_ERR_MODIFIED, krbError.ErrorCode, "SMB Server should return {0}", KRB_ERROR_CODE.KRB_AP_ERR_MODIFIED); } smb2Client.Disconnect(); return; } if (variant.HasFlag(CaseVariant.AUTHENTICATOR_EXCEED_TIME_SKEW)) { BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because the server time and the client time " + "in the Authenticator differ by (1 hour) more than the allowable clock skew"); if (TestConfig.IsWindowsPlatform) { KerberosKrbError krbError = kerberosClient.GetKrbErrorFromToken(repToken); BaseTestSite.Assert.AreEqual(KRB_ERROR_CODE.KRB_AP_ERR_SKEW, krbError.ErrorCode, "SMB Server should return {0}", KRB_ERROR_CODE.KRB_AP_ERR_SKEW); } smb2Client.Disconnect(); return; } if (variant.HasFlag(CaseVariant.TICKET_WRONG_KVNO) || variant.HasFlag(CaseVariant.TICKET_WRONG_REALM) || variant.HasFlag(CaseVariant.TICKET_WRONG_SNAME)) { BaseTestSite.Log.Add(LogEntryKind.Comment, "If decryption fails, server would try other keys"); } if (variant.HasFlag(CaseVariant.TICKET_NOT_VALID)) { BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because the starttime (tomorrow) in the Ticket " + "is later than the current time by more than the allowable clock skew"); if (TestConfig.IsWindowsPlatform) { KerberosKrbError krbError = kerberosClient.GetKrbErrorFromToken(repToken); BaseTestSite.Assert.AreEqual(KRB_ERROR_CODE.KRB_AP_ERR_TKT_NYV, krbError.ErrorCode, "SMB Server should return {0}", KRB_ERROR_CODE.KRB_AP_ERR_TKT_NYV); } smb2Client.Disconnect(); return; } if (variant.HasFlag(CaseVariant.TICKET_EXPIRED)) { BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because the current time is later than the endtime (yesterday)" + " in the Ticket by more than the allowable clock skew"); if (TestConfig.IsWindowsPlatform) { KerberosKrbError krbError = kerberosClient.GetKrbErrorFromToken(repToken); BaseTestSite.Assert.AreEqual(KRB_ERROR_CODE.KRB_AP_ERR_TKT_EXPIRED, krbError.ErrorCode, "SMB Server should return {0}", KRB_ERROR_CODE.KRB_AP_ERR_TKT_EXPIRED); } smb2Client.Disconnect(); return; } if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_TKT)) { BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because of the unknown AutherizationData in the ticket"); smb2Client.Disconnect(); return; } if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_AUTHENTICATOR)) { BaseTestSite.Log.Add(LogEntryKind.Comment, "Unknown AuthorizationData in the Authenticator should not fail the request"); } if (variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_TKT_OPTIONAL) || variant.HasFlag(CaseVariant.AUTHDATA_UNKNOWN_TYPE_IN_AUTHENTICATOR_OPTIONAL)) { BaseTestSite.Log.Add(LogEntryKind.Comment, "Unknown AuthorizationData in AD_IF_RELEVANT is optional. " + "Server should not fail the request."); } KerberosApResponse apRep = kerberosClient.GetApResponseFromToken(repToken, GssToken); // Get subkey from AP response, which used for signing in smb2 apRep.Decrypt(kerberosClient.Context.Ticket.SessionKey.keyvalue.ByteArrayValue); smb2Client.SetSessionSigningAndEncryption(true, false, apRep.ApEncPart.subkey.keyvalue.ByteArrayValue); string path = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare); AccessFile(smb2Client, path); #endregion smb2Client.LogOff(); smb2Client.Disconnect(); }
public void KerbAuth_Replay() { #region Get Service Ticket BaseTestSite.Log.Add(LogEntryKind.TestStep, "Initialize Kerberos Functional Client"); KerberosFunctionalClient kerberosClient = new KerberosFunctionalClient( TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, KerberosAccountType.User, KDCIP, KDCPort, TransportType.TCP, OidPkt, BaseTestSite); //Create and send AS request const KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE; kerberosClient.SendAsRequest(options, null); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client expects Kerberos Error from KDC"); //Receive preauthentication required error METHOD_DATA methodData; KerberosKrbError krbError = kerberosClient.ExpectPreauthRequiredError(out methodData); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client sends AS request with PA-DATA set"); //Create sequence of PA data string timeStamp = KerberosUtility.CurrentKerberosTime.Value; PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, kerberosClient.Context.SelectedEType, kerberosClient.Context.CName.Password, kerberosClient.Context.CName.Salt); PaPacRequest paPacRequest = new PaPacRequest(true); Asn1SequenceOf <PA_DATA> seqOfPaData = new Asn1SequenceOf <PA_DATA>(new[] { paEncTimeStamp.Data, paPacRequest.Data }); //Create and send AS request kerberosClient.SendAsRequest(options, seqOfPaData); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client expects AS response from KDC"); KerberosAsResponse asResponse = kerberosClient.ExpectAsResponse(); BaseTestSite.Assert.IsNotNull(asResponse.Response.ticket, "AS response should contain a TGT."); //Create and send TGS request BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client sends TGS request to KDC"); kerberosClient.SendTgsRequest(servicePrincipalName, options); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Kerberos Functional Client expects TGS response from KDC"); KerberosTgsResponse tgsResponse = kerberosClient.ExpectTgsResponse(); BaseTestSite.Assert.AreEqual(servicePrincipalName, KerberosUtility.PrincipalName2String(tgsResponse.Response.ticket.sname), "Service principal name in service ticket should match expected."); #endregion #region Create AP request Ticket serviceTicket = kerberosClient.Context.Ticket.Ticket; Realm crealm = serviceTicket.realm; EncryptionKey subkey = KerberosUtility.GenerateKey(kerberosClient.Context.SessionKey); PrincipalName cname = kerberosClient.Context.CName.Name; Authenticator authenticator = CreateAuthenticator(cname, crealm, subkey); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create AP Request"); KerberosApRequest request = new KerberosApRequest( kerberosClient.Context.Pvno, new APOptions(KerberosUtility.ConvertInt2Flags((int)ApOptions.MutualRequired)), kerberosClient.Context.Ticket, authenticator, KeyUsageNumber.AP_REQ_Authenticator ); #endregion #region Create GSS token and send session setup request BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create GSS Token"); byte[] token = KerberosUtility.AddGssApiTokenHeader(request, OidPkt, GssToken); Smb2FunctionalClientForKerbAuth smb2Client = new Smb2FunctionalClientForKerbAuth(TestConfig.Timeout, TestConfig, BaseTestSite); smb2Client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); byte[] repToken; uint status = DoSessionSetupWithGssToken(smb2Client, token, out repToken); KerberosApResponse apRep = kerberosClient.GetApResponseFromToken(repToken, GssToken); // Get subkey from AP response, which used for signing in smb2 apRep.Decrypt(kerberosClient.Context.Ticket.SessionKey.keyvalue.ByteArrayValue); smb2Client.SetSessionSigningAndEncryption(true, false, apRep.ApEncPart.subkey.keyvalue.ByteArrayValue); #endregion #region Second client BaseTestSite.Log.Add(LogEntryKind.TestStep, "Replay the request from another client"); Smb2FunctionalClientForKerbAuth smb2Client2 = new Smb2FunctionalClientForKerbAuth(TestConfig.Timeout, TestConfig, BaseTestSite); smb2Client2.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); status = DoSessionSetupWithGssToken(smb2Client2, token, out repToken); BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, status, "Session Setup should fail because it uses a Replay of KRB_AP_REQ"); if (TestConfig.IsWindowsPlatform) { krbError = kerberosClient.GetKrbErrorFromToken(repToken); BaseTestSite.Assert.AreEqual(KRB_ERROR_CODE.KRB_AP_ERR_REPEAT, krbError.ErrorCode, "SMB Server should return {0}", KRB_ERROR_CODE.KRB_AP_ERR_REPEAT); } smb2Client2.Disconnect(); #endregion string path = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare); AccessFile(smb2Client, path); smb2Client.LogOff(); smb2Client.Disconnect(); }