//Ticket::= [APPLICATION 1] SEQUENCE { // tkt-vno[0] INTEGER(5), // realm[1] Realm, // sname[2] PrincipalName, // enc-part[3] EncryptedData -- EncTicketPart //} public Ticket(AsnElt body) { foreach (AsnElt s in body.EnumerateElements()) { AsnElt firstItem = s.FirstElement; switch (s.TagValue) { case 0: tkt_vno = Convert.ToInt32(firstItem.GetInteger()); break; case 1: realm = Encoding.ASCII.GetString(firstItem.GetOctetString()); break; case 2: sname = new PrincipalName(firstItem); break; case 3: enc_part = new EncryptedData(firstItem); break; default: break; } } }
public PA_FOR_USER(byte[] key, string name, string realm) { userName = new PrincipalName(name); userName.name_type = Interop.PRINCIPAL_TYPE.NT_ENTERPRISE; userRealm = realm; // now build the checksum auth_package = "Kerberos"; byte[] nameTypeBytes = new byte[4]; nameTypeBytes[0] = 0xa; byte[] nameBytes = Encoding.UTF8.GetBytes(name); byte[] realmBytes = Encoding.UTF8.GetBytes(userRealm); byte[] authPackageBytes = Encoding.UTF8.GetBytes(auth_package); byte[] finalBytes = new byte[nameTypeBytes.Length + nameBytes.Length + realmBytes.Length + authPackageBytes.Length]; Array.Copy(nameTypeBytes, 0, finalBytes, 0, nameTypeBytes.Length); Array.Copy(nameBytes, 0, finalBytes, nameTypeBytes.Length, nameBytes.Length); Array.Copy(realmBytes, 0, finalBytes, nameTypeBytes.Length + nameBytes.Length, realmBytes.Length); Array.Copy(authPackageBytes, 0, finalBytes, nameTypeBytes.Length + nameBytes.Length + realmBytes.Length, authPackageBytes.Length); byte[] outBytes = Crypto.KerberosChecksum(key, finalBytes); Checksum checksum = new Checksum(outBytes); cksum = checksum; }
public Ticket(AsnElt body) { foreach (AsnElt s in body.Sub) { switch (s.TagValue) { case 0: tkt_vno = Convert.ToInt32(s.Sub[0].GetInteger()); break; case 1: realm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 2: sname = new PrincipalName(s.Sub[0]); break; case 3: enc_part = new EncryptedData(s.Sub[0]); break; default: break; } } }
//EncTicketPart::= [APPLICATION 3] SEQUENCE { // flags[0] TicketFlags, // key[1] EncryptionKey, // crealm[2] Realm, // cname[3] PrincipalName, // transited[4] TransitedEncoding, // authtime[5] KerberosTime, // starttime[6] KerberosTime OPTIONAL, // endtime[7] KerberosTime, // renew-till[8] KerberosTime OPTIONAL, // caddr[9] HostAddresses OPTIONAL, // authorization-data[10] AuthorizationData OPTIONAL //} public EncTicketPart(byte[] sessionKey, Interop.KERB_ETYPE etype, string domain, string user, Interop.TicketFlags ticketFlags, DateTime startTime) { // flags flags = ticketFlags; // default times authtime = startTime; starttime = startTime; endtime = starttime.AddHours(10); renew_till = starttime.AddDays(7); // set session key key = new EncryptionKey(); key.keytype = (int)etype; key.keyvalue = sessionKey; // cname information crealm = domain; cname = new PrincipalName(user); // default empty TransitedEncoding transited = new TransitedEncoding(); // null caddr and authdata caddr = null; authorization_data = null; }
public EncTicketPart(AsnElt body) { foreach (AsnElt s in body.Sub) { switch (s.TagValue) { case 0: UInt32 temp = Convert.ToUInt32(s.Sub[0].GetInteger()); byte[] tempBytes = BitConverter.GetBytes(temp); flags = (Interop.TicketFlags)BitConverter.ToInt32(tempBytes, 0); break; case 1: key = new EncryptionKey(s); break; case 2: crealm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 3: cname = new PrincipalName(s.Sub[0]); break; case 4: transited = new TransitedEncoding(s.Sub[0]); break; case 5: authtime = s.Sub[0].GetTime(); break; case 6: starttime = s.Sub[0].GetTime(); break; case 7: endtime = s.Sub[0].GetTime(); break; case 8: renew_till = s.Sub[0].GetTime(); break; case 9: // caddr (optional) caddr = new List <HostAddress>(); caddr.Add(new HostAddress(s.Sub[0])); break; case 10: // authorization-data (optional) authorization_data = new AuthorizationData(s.Sub[0]); break; default: break; } } }
//KDC-REQ-BODY::= SEQUENCE { // kdc-options[0] KDCOptions, // cname[1] PrincipalName OPTIONAL // -- Used only in AS-REQ --, // realm[2] Realm // -- Server's realm // -- Also client's in AS-REQ --, // sname[3] PrincipalName OPTIONAL, // from[4] KerberosTime OPTIONAL, // till[5] KerberosTime, // rtime[6] KerberosTime OPTIONAL, // nonce[7] UInt32, // etype[8] SEQUENCE OF Int32 -- EncryptionType // -- in preference order --, // addresses[9] HostAddresses OPTIONAL, // enc-authorization-data[10] EncryptedData OPTIONAL // -- AuthorizationData --, // additional-tickets[11] SEQUENCE OF Ticket OPTIONAL // -- NOTE: not empty //} public KDCReqBody(bool c = true) { // defaults for creation kdcOptions = Interop.KdcOptions.FORWARDABLE | Interop.KdcOptions.RENEWABLE | Interop.KdcOptions.RENEWABLEOK; // added ability to remove cname from request // seems to be useful for cross domain stuff // didn't see a cname in "real" S4U request traffic if (c) { cname = new PrincipalName(); } sname = new PrincipalName(); // date time from kekeo ;) HAI 2037! till = DateTime.ParseExact("20370913024805Z", "yyyyMMddHHmmssZ", System.Globalization.CultureInfo.InvariantCulture); var rand = new Random(); nonce = (UInt32)rand.Next(1, Int32.MaxValue); additional_tickets = new List <Ticket>(); etypes = new List <Interop.KERB_ETYPE>(); }
private void Decode(AsnElt asn_AS_REP) { // AS-REP::= [APPLICATION 11] KDC-REQ if (asn_AS_REP.TagValue != (int)Interop.KERB_MESSAGE_TYPE.AS_REP) { throw new System.Exception("AS-REP tag value should be 11"); } if ((asn_AS_REP.Sub.Length != 1) || (asn_AS_REP.Sub[0].TagValue != 16)) { throw new System.Exception("First AS-REP sub should be a sequence"); } // extract the KDC-REP out AsnElt[] kdc_rep = asn_AS_REP.Sub[0].Sub; padata = new List <PA_DATA>(); foreach (AsnElt s in kdc_rep) { switch (s.TagValue) { case 0: pvno = s.Sub[0].GetInteger(); break; case 1: msg_type = s.Sub[0].GetInteger(); break; case 2: // sequence of pa-data foreach (AsnElt pad in s.Sub) { padata.Add(new PA_DATA(pad.Sub[0])); } break; case 3: crealm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 4: cname = new PrincipalName(s.Sub[0]); break; case 5: ticket = new Ticket(s.Sub[0].Sub[0]); break; case 6: enc_part = new EncryptedData(s.Sub[0]); break; default: break; } } }
//KrbCredInfo ::= SEQUENCE { // key [0] EncryptionKey, // prealm [1] Realm OPTIONAL, // pname [2] PrincipalName OPTIONAL, // flags [3] TicketFlags OPTIONAL, // authtime [4] KerberosTime OPTIONAL, // starttime [5] KerberosTime OPTIONAL, // endtime [6] KerberosTime OPTIONAL, // renew-till [7] KerberosTime OPTIONAL, // srealm [8] Realm OPTIONAL, // sname [9] PrincipalName OPTIONAL, // caddr [10] HostAddresses OPTIONAL //} public KrbCredInfo() { key = new EncryptionKey(); prealm = string.Empty; pname = new PrincipalName(); flags = 0; srealm = string.Empty; sname = new PrincipalName(); }
public AsnElt Encode() { // user-data [0] OCTET STRING byte[] pwBytes = Encoding.ASCII.GetBytes(new_password); AsnElt new_passwordAsn = AsnElt.MakeBlob(pwBytes); AsnElt new_passwordSeq; if (username == null) { new_passwordSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { AsnElt.MakeExplicit(AsnElt.CONTEXT, 0, new_passwordAsn), }); } else { PrincipalName principal = new PrincipalName(username); new_passwordSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { AsnElt.MakeExplicit(AsnElt.CONTEXT, 0, new_passwordAsn), AsnElt.MakeImplicit(AsnElt.CONTEXT, 1, principal.Encode()), AsnElt.MakeExplicit(AsnElt.CONTEXT, 2, AsnElt.MakeString(AsnElt.GeneralString, realm)), }); } new_passwordSeq = AsnElt.MakeExplicit(AsnElt.CONTEXT, 0, AsnElt.MakeBlob(new_passwordSeq.Encode())); // seq-number [3] UInt32 OPTIONAL AsnElt seq_numberAsn = AsnElt.MakeInteger(seq_number); AsnElt seq_numberSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { seq_numberAsn }); seq_numberSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 3, seq_numberSeq); // s-address [4] HostAddress AsnElt hostAddressTypeAsn = AsnElt.MakeInteger(20); AsnElt hostAddressTypeSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { hostAddressTypeAsn }); hostAddressTypeSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 0, hostAddressTypeSeq); byte[] hostAddressAddressBytes = Encoding.ASCII.GetBytes(host_name); AsnElt hostAddressAddressAsn = AsnElt.MakeBlob(hostAddressAddressBytes); AsnElt hostAddressAddressSeq = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { hostAddressAddressAsn }); hostAddressAddressSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 1, hostAddressAddressSeq); AsnElt hostAddressSeq = AsnElt.Make(AsnElt.SEQUENCE, new[] { hostAddressTypeSeq, hostAddressAddressSeq }); AsnElt hostAddressSeq2 = AsnElt.Make(AsnElt.SEQUENCE, new AsnElt[] { hostAddressSeq }); hostAddressSeq2 = AsnElt.MakeImplicit(AsnElt.CONTEXT, 4, hostAddressSeq2); AsnElt seq = AsnElt.Make(AsnElt.SEQUENCE, new[] { new_passwordSeq, seq_numberSeq, hostAddressSeq2 }); AsnElt seq2 = AsnElt.Make(AsnElt.SEQUENCE, new[] { seq }); seq2 = AsnElt.MakeImplicit(AsnElt.APPLICATION, 28, seq2); return(seq2); }
public KRB_ERROR(AsnElt body) { foreach (AsnElt s in body.EnumerateElements()) { AsnElt firstElement = s.FirstElement; switch (s.TagValue) { case 0: pvno = Convert.ToUInt32(firstElement.GetInteger()); break; case 1: msg_type = Convert.ToUInt32(firstElement.GetInteger()); break; case 2: ctime = firstElement.GetTime(); break; case 3: cusec = Convert.ToUInt32(firstElement.GetInteger()); break; case 4: stime = firstElement.GetTime(); break; case 5: susec = Convert.ToUInt32(firstElement.GetInteger()); break; case 6: ErrorCode = Convert.ToUInt32(firstElement.GetInteger()); break; case 7: crealm = Encoding.ASCII.GetString(firstElement.GetOctetString()); break; case 8: cname = new PrincipalName(firstElement); break; case 9: realm = Encoding.ASCII.GetString(firstElement.GetOctetString()); break; case 10: sname = new PrincipalName(firstElement); break; default: break; } } }
//Authenticator ::= [APPLICATION 2] SEQUENCE { // authenticator-vno [0] INTEGER (5), // crealm [1] Realm, // cname [2] PrincipalName, // cksum [3] Checksum OPTIONAL, // cusec [4] Microseconds, // ctime [5] KerberosTime, // subkey [6] EncryptionKey OPTIONAL, // seq-number [7] UInt32 OPTIONAL, // authorization-data [8] AuthorizationData OPTIONAL //} // NOTE: we're only using: // authenticator-vno [0] // crealm [1] // cname [2] // cusec [4] // ctime [5] public Authenticator() { authenticator_vno = 5; crealm = ""; cname = new PrincipalName(); cusec = 0; ctime = DateTime.UtcNow; subkey = null; seq_number = 0; }
public KRB_ERROR(AsnElt body) { foreach (AsnElt s in body.Sub) { switch (s.TagValue) { case 0: pvno = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 1: msg_type = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 2: ctime = s.Sub[0].GetTime(); break; case 3: cusec = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 4: stime = s.Sub[0].GetTime(); break; case 5: susec = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 6: error_code = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 7: crealm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 8: cname = new PrincipalName(s.Sub[0]); break; case 9: realm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 10: sname = new PrincipalName(s.Sub[0]); break; default: break; } } }
public KrbCredInfo(AsnElt body) { foreach (AsnElt s in body.EnumerateElements()) { AsnElt firstElement = s.FirstElement; switch (s.TagValue) { case 0: key = new EncryptionKey(s); break; case 1: prealm = Encoding.ASCII.GetString(firstElement.GetOctetString()); break; case 2: pname = new PrincipalName(firstElement); break; case 3: UInt32 temp = Convert.ToUInt32(firstElement.GetInteger()); byte[] tempBytes = BitConverter.GetBytes(temp); flags = (Interop.TicketFlags)BitConverter.ToInt32(tempBytes, 0); break; case 4: authtime = firstElement.GetTime(); break; case 5: starttime = firstElement.GetTime(); break; case 6: endtime = firstElement.GetTime(); break; case 7: renew_till = firstElement.GetTime(); break; case 8: srealm = Encoding.ASCII.GetString(firstElement.GetOctetString()); break; case 9: sname = new PrincipalName(firstElement); break; default: break; } } }
private void Decode(AsnElt asn_TGS_REP) { // TGS - REP::= [APPLICATION 13] KDC - REP if (asn_TGS_REP.TagValue != 13) { throw new System.Exception("TGS-REP tag value should be 11"); } if ((asn_TGS_REP.Sub.Length != 1) || (asn_TGS_REP.Sub[0].TagValue != 16)) { throw new System.Exception("First TGS-REP sub should be a sequence"); } // extract the KDC-REP out AsnElt[] kdc_rep = asn_TGS_REP.Sub[0].Sub; foreach (AsnElt s in kdc_rep) { switch (s.TagValue) { case 0: pvno = s.Sub[0].GetInteger(); break; case 1: msg_type = s.Sub[0].GetInteger(); break; case 2: // sequence of pa-data padata = new PA_DATA(s.Sub[0]); break; case 3: crealm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 4: cname = new PrincipalName(s.Sub[0]); break; case 5: ticket = new Ticket(s.Sub[0].Sub[0]); break; case 6: enc_part = new EncryptedData(s.Sub[0]); break; default: break; } } }
public S4UUserID(string name, string realm, uint n) { nonce = n; cname = new PrincipalName(name); cname.name_type = Interop.PRINCIPAL_TYPE.NT_ENTERPRISE; crealm = realm; // default for creation options = Interop.PA_S4U_X509_USER_OPTIONS.SIGN_REPLY; }
//Authenticator ::= [APPLICATION 2] SEQUENCE { // authenticator-vno [0] INTEGER (5), // crealm [1] Realm, // cname [2] PrincipalName, // cksum [3] Checksum OPTIONAL, // cusec [4] Microseconds, // ctime [5] KerberosTime, // subkey [6] EncryptionKey OPTIONAL, // seq-number [7] UInt32 OPTIONAL, // authorization-data [8] AuthorizationData OPTIONAL //} // NOTE: we're only using: // authenticator-vno [0] // crealm [1] // cname [2] // cusec [4] // ctime [5] public Authenticator() { authenticator_vno = 5; crealm = ""; cname = new PrincipalName(); cusec = 0; ctime = DateTime.UtcNow; }
private void Decode(AsnElt asn_TGS_REP) { // TGS - REP::= [APPLICATION 13] KDC - REP if (asn_TGS_REP.TagValue != 13) { throw new System.Exception("TGS-REP tag value should be 11"); } if ((asn_TGS_REP.Count != 1) || (asn_TGS_REP.FirstElement.TagValue != 16)) { throw new System.Exception("First TGS-REP sub should be a sequence"); } // extract the KDC-REP out foreach (AsnElt s in asn_TGS_REP.FirstElement.EnumerateElements()) { AsnElt firstElement = s.FirstElement; switch (s.TagValue) { case 0: pvno = firstElement.GetInteger(); break; case 1: msg_type = firstElement.GetInteger(); break; case 2: // sequence of pa-data padata = new PA_DATA(firstElement); break; case 3: crealm = Encoding.ASCII.GetString(firstElement.GetOctetString()); break; case 4: cname = new PrincipalName(firstElement); break; case 5: ticket = new Ticket(firstElement.FirstElement); break; case 6: enc_part = new EncryptedData(firstElement); break; default: break; } } }
//Ticket::= [APPLICATION 1] SEQUENCE { // tkt-vno[0] INTEGER(5), // realm[1] Realm, // sname[2] PrincipalName, // enc-part[3] EncryptedData -- EncTicketPart //} public Ticket(string domain, string service) { tkt_vno = 5; realm = domain; sname = new PrincipalName(); sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_INST; foreach (string part in service.Split('/')) { sname.name_string.Add(part); } }
//KDC-REQ-BODY::= SEQUENCE { // kdc-options[0] KDCOptions, // cname[1] PrincipalName OPTIONAL // -- Used only in AS-REQ --, // realm[2] Realm // -- Server's realm // -- Also client's in AS-REQ --, // sname[3] PrincipalName OPTIONAL, // from[4] KerberosTime OPTIONAL, // till[5] KerberosTime, // rtime[6] KerberosTime OPTIONAL, // nonce[7] UInt32, // etype[8] SEQUENCE OF Int32 -- EncryptionType // -- in preference order --, // addresses[9] HostAddresses OPTIONAL, // enc-authorization-data[10] EncryptedData OPTIONAL // -- AuthorizationData --, // additional-tickets[11] SEQUENCE OF Ticket OPTIONAL // -- NOTE: not empty //} public KDCReqBody() { // defaults for creation kdcOptions = Interop.KdcOptions.FORWARDABLE | Interop.KdcOptions.RENEWABLE | Interop.KdcOptions.RENEWABLEOK; cname = new PrincipalName(); sname = new PrincipalName(); // date time from kekeo ;) HAI 2037! till = DateTime.ParseExact("20370913024805Z", Constants.UTCTimeFormat, System.Globalization.CultureInfo.InvariantCulture); // kekeo/mimikatz nonce ;) //nonce = 12381973; nonce = 1818848256; additional_tickets = new List <Ticket>(); etypes = new List <Interop.KERB_ETYPE>(); }
public KRB_ERROR(AsnElt body) { foreach (AsnElt s in body.Sub) { switch (s.TagValue) { case 0: pvno = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 1: msg_type = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 2: ctime = s.Sub[0].GetTime(); break; case 3: cusec = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 4: stime = s.Sub[0].GetTime(); break; case 5: susec = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 6: error_code = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 7: crealm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 8: cname = new PrincipalName(s.Sub[0]); break; case 9: realm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 10: sname = new PrincipalName(s.Sub[0]); break; case 11: e_text = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 12: try { e_data = new List <PA_DATA>(); AsnElt tmpData = AsnElt.Decode(s.Sub[0].GetOctetString()); foreach (AsnElt tmp in tmpData.Sub) { e_data.Add(new PA_DATA(tmp)); } } catch (NullReferenceException ex) { e_data = null; } break; default: break; } } }
//EncKDCRepPart::= SEQUENCE { // key[0] EncryptionKey, // last-req[1] LastReq, // nonce[2] UInt32, // key-expiration[3] KerberosTime OPTIONAL, // flags[4] TicketFlags, // authtime[5] KerberosTime, // starttime[6] KerberosTime OPTIONAL, // endtime[7] KerberosTime, // renew-till[8] KerberosTime OPTIONAL, // srealm[9] Realm, // sname[10] PrincipalName, // caddr[11] HostAddresses OPTIONAL, // encrypted-pa-data[12] SEQUENCE OF PA-DATA OPTIONAL //} public EncKDCRepPart(AsnElt body) { foreach (AsnElt s in body.EnumerateElements()) { AsnElt firstElement = s.FirstElement; switch (s.TagValue) { case 0: key = new EncryptionKey(s); break; case 1: lastReq = new LastReq(firstElement); break; case 2: nonce = Convert.ToUInt32(firstElement.GetInteger()); break; case 3: key_expiration = firstElement.GetTime(); break; case 4: UInt32 temp = Convert.ToUInt32(firstElement.GetInteger()); byte[] tempBytes = BitConverter.GetBytes(temp); flags = (Interop.TicketFlags)BitConverter.ToInt32(tempBytes, 0); break; case 5: authtime = firstElement.GetTime(); break; case 6: starttime = firstElement.GetTime(); break; case 7: endtime = firstElement.GetTime(); break; case 8: renew_till = firstElement.GetTime(); break; case 9: realm = Encoding.ASCII.GetString(firstElement.GetOctetString()); break; case 10: // sname (optional) sname = new PrincipalName(firstElement); break; case 11: // HostAddresses, skipped for now break; case 12: // encrypted-pa-data, skipped for now break; default: break; } } }
public KDCReqBody(AsnElt body) { foreach (AsnElt s in body.Sub) { switch (s.TagValue) { case 0: UInt32 temp = Convert.ToUInt32(s.Sub[0].GetInteger()); byte[] tempBytes = BitConverter.GetBytes(temp); kdcOptions = (Interop.KdcOptions)BitConverter.ToInt32(tempBytes, 0); break; case 1: // optional cname = new PrincipalName(s.Sub[0]); break; case 2: realm = Encoding.ASCII.GetString(s.Sub[0].GetOctetString()); break; case 3: // optional sname = new PrincipalName(s.Sub[0]); break; case 4: // optional from = s.Sub[0].GetTime(); break; case 5: till = s.Sub[0].GetTime(); break; case 6: // optional rtime = s.Sub[0].GetTime(); break; case 7: nonce = Convert.ToUInt32(s.Sub[0].GetInteger()); break; case 8: //etypes = new Enums.KERB_ETYPE[s.Sub[0].Sub.Length]; etypes = new List <Interop.KERB_ETYPE>(); for (int i = 0; i < s.Sub[0].Sub.Length; i++) { //etypes[i] = (Enums.KERB_ETYPE)Convert.ToUInt32(s.Sub[0].Sub[i].GetInteger()); etypes.Add((Interop.KERB_ETYPE)Convert.ToUInt32(s.Sub[0].Sub[i].GetInteger())); } break; case 9: // addresses (optional) break; case 10: // enc authorization-data (optional) break; case 11: // additional-tickets (optional) break; default: break; } } }