Loading plugin/ad/ad.cpp +6 −3 Changes for plugin/ad/ad.cpp: 6 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -1247,7 +1247,7 @@ void ActiveDirectory::RequestEvent(netplus::con &curcon, const int, ULONG_PTR) { if (!responses.empty()) { fenrirds::crypto::Bytes resp(responses.begin(), responses.end()); auto wrapped = gss::wrap(session->gssKey, session->gssEtype, true, session->sendSeq++, resp, session->ssf == 2); session->ssf == 2, session->gssAccSubkey); uint32_t wl = uint32_t(wrapped.size()); curcon.SendData.push_back(char(wl >> 24)); curcon.SendData.push_back(char(wl >> 16)); Loading Loading @@ -1529,6 +1529,7 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content, session.gssState = LdapSession::GssSentApRep; session.sendSeq = res.acceptorSeq; session.recvSeq = res.initiatorSeq; session.gssAccSubkey = res.acceptorSubkey; std::vector<uint8_t> krb5reply; if (!res.apRep.empty()) { Loading @@ -1544,7 +1545,8 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content, if (spnego) { std::vector<uint8_t> krb5oid = gss::firstMechOid(session.gssMechTypes); std::vector<uint8_t> mic = gss::getMic(session.gssKey, session.gssEtype, true, session.sendSeq++, session.gssMechTypes); true, session.sendSeq++, session.gssMechTypes, session.gssAccSubkey); creds = gss::buildSpnegoResp(gss::ACCEPT_COMPLETED, &krb5oid, krb5reply, mic); /* GSS-SPNEGO has no RFC 4752 layer negotiation: the bind is * done, and the client signs or seals the following PDUs as Loading @@ -1568,7 +1570,8 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content, * with a max receive buffer. Wrapped (sign) with the context key. */ uint32_t maxBuf = 0x000FFFFF; std::vector<uint8_t> sec = {0x07, uint8_t(maxBuf >> 16), uint8_t(maxBuf >> 8), uint8_t(maxBuf)}; auto tok = gss::wrap(session.gssKey, session.gssEtype, true, session.sendSeq++, sec); auto tok = gss::wrap(session.gssKey, session.gssEtype, true, session.sendSeq++, sec, false, session.gssAccSubkey); session.gssState = LdapSession::GssSentSecLayer; return bindResp(SASL_BIND_IN_PROGRESS, &tok); } Loading plugin/ad/ad.h +1 −0 Changes for plugin/ad/ad.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -228,6 +228,7 @@ namespace fenrirds { int ssf = 0; uint64_t sendSeq = 0; /* acceptor -> client */ uint64_t recvSeq = 0; /* client -> acceptor */ bool gssAccSubkey = false; /* context key = our AP-REP subkey */ }; /*************************************************************************** Loading plugin/krb5/krb5.cpp +21 −3 Changes for plugin/krb5/krb5.cpp: 21 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -3882,6 +3882,20 @@ bool Krb5KDC::gssAccept(const std::vector<uint8_t> &apReqData, GssAcceptResult & out.acceptorSeq = variant == 0 ? (Krb5Crypto::randomNonce() & 0x3fffffff) : 0; if (ap.ap_options & 0x20000000) { Krb5Service svc("", "", ap.ticket.sname.realm, svcKey); /* Like Windows and Heimdal acceptors, assert our own subkey for AES * contexts: it becomes the GSS context key (MIC, wrap, the SMB * session key); our tokens then carry the AcceptorSubkey flag. */ Krb5SessionKey accKey; int accEtype = auth.has_subkey ? auth.subkey.enctype : et.session_key.enctype; bool useAccKey = variant == 0 && (accEtype == KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1 || accEtype == KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1); if (useAccKey) { accKey.enctype = static_cast<Krb5EncType>(accEtype); accKey.keydata = Krb5Crypto::randomBytes(accEtype == KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1 ? 32 : 16); out.sessionKey = accKey.keydata; out.sessionEtype = accEtype; out.acceptorSubkey = true; } if (variant == 3) { auto legacy = Asn1Der::encodePaEncTimestamp(auth.ctime, auth.cusec); Krb5ApRep ap_rep; Loading @@ -3892,13 +3906,14 @@ bool Krb5KDC::gssAccept(const std::vector<uint8_t> &apReqData, GssAcceptResult & ap_rep.enc_part = Krb5Crypto::encrypt(et.session_key.keydata, legacy, KRB5_KU_AP_REP_ENC_PART); out.apRep = ap_rep.serialize(); } else { out.apRep = svc.buildApRep(auth, et.session_key, out.acceptorSeq); out.apRep = svc.buildApRep(auth, et.session_key, out.acceptorSeq, useAccKey ? &accKey : nullptr); } } out.gssFlags = auth.has_gss_cksum ? auth.gss_flags : 0; out.initiatorSeq = auth.seq_number; std::cerr << "[KDC] gssAccept " << out.clientPrincipal << " variant=" << "ABCD"[out.apRepVariant] << " subkey=" << auth.has_subkey << " subkey=" << auth.has_subkey << " accSubkey=" << out.acceptorSubkey << " flags=0x" << std::hex << out.gssFlags << " initSeq=0x" << out.initiatorSeq << " accSeq=0x" << out.acceptorSeq << std::dec << " mutual=" << !out.apRep.empty() << std::endl; return true; Loading Loading @@ -4435,7 +4450,8 @@ bool Krb5Service::verifyApReq(const std::vector<uint8_t> &apReqData, std::vector<uint8_t> Krb5Service::buildApRep(const Krb5Authenticator &auth, const Krb5SessionKey &sessionKey, uint32_t seqNumber) { uint32_t seqNumber, const Krb5SessionKey *subkey) { /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE { * ctime [0] KerberosTime, cusec [1] Microseconds, * subkey [2] EncryptionKey OPTIONAL, seq-number [3] UInt32 OPTIONAL } Loading @@ -4446,6 +4462,8 @@ std::vector<uint8_t> Krb5Service::buildApRep(const Krb5Authenticator &auth, std::vector<uint8_t> seq; Asn1Der::encodeContextTag(seq, 0, Asn1Der::encodeGeneralizedTime(auth.ctime)); Asn1Der::encodeContextTag(seq, 1, Asn1Der::encodeUInteger(auth.cusec)); if (subkey && !subkey->keydata.empty()) Asn1Der::encodeContextTag(seq, 2, Asn1Der::encodeEncryptionKey(*subkey)); Asn1Der::encodeContextTag(seq, 3, Asn1Der::encodeUInteger(seqNumber & 0x7fffffff)); std::vector<uint8_t> repData; Asn1Der::encodeTLV(repData, 0x7B /* [APPLICATION 27] */, Asn1Der::encodeSequence(seq)); Loading plugin/krb5/krb5.h +2 −1 Changes for plugin/krb5/krb5.h: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -927,7 +927,8 @@ namespace fenrirds { /* Build an AP-REP response */ std::vector<uint8_t> buildApRep(const Krb5Authenticator &auth, const Krb5SessionKey &sessionKey, uint32_t seqNumber = 0); uint32_t seqNumber = 0, const Krb5SessionKey *subkey = nullptr); private: Krb5Principal _ServicePrincipal; Loading plugin/smb/smb.cpp +2 −1 Changes for plugin/smb/smb.cpp: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -753,7 +753,8 @@ SmbServer::Reply SmbServer::sessionSetup(Conn &c, const smb::Smb2Header &req, std::vector<uint8_t> outTok; if (spnego) { std::vector<uint8_t> oid = gss::firstMechOid(mechTypes); auto m = gss::getMic(res.sessionKey, res.sessionEtype, true, res.acceptorSeq, mechTypes); auto m = gss::getMic(res.sessionKey, res.sessionEtype, true, res.acceptorSeq, mechTypes, res.acceptorSubkey); outTok = gss::buildSpnegoResp(gss::ACCEPT_COMPLETED, &oid, krb5reply, m); } else { outTok = krb5reply; Loading Loading
plugin/ad/ad.cpp +6 −3 Changes for plugin/ad/ad.cpp: 6 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -1247,7 +1247,7 @@ void ActiveDirectory::RequestEvent(netplus::con &curcon, const int, ULONG_PTR) { if (!responses.empty()) { fenrirds::crypto::Bytes resp(responses.begin(), responses.end()); auto wrapped = gss::wrap(session->gssKey, session->gssEtype, true, session->sendSeq++, resp, session->ssf == 2); session->ssf == 2, session->gssAccSubkey); uint32_t wl = uint32_t(wrapped.size()); curcon.SendData.push_back(char(wl >> 24)); curcon.SendData.push_back(char(wl >> 16)); Loading Loading @@ -1529,6 +1529,7 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content, session.gssState = LdapSession::GssSentApRep; session.sendSeq = res.acceptorSeq; session.recvSeq = res.initiatorSeq; session.gssAccSubkey = res.acceptorSubkey; std::vector<uint8_t> krb5reply; if (!res.apRep.empty()) { Loading @@ -1544,7 +1545,8 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content, if (spnego) { std::vector<uint8_t> krb5oid = gss::firstMechOid(session.gssMechTypes); std::vector<uint8_t> mic = gss::getMic(session.gssKey, session.gssEtype, true, session.sendSeq++, session.gssMechTypes); true, session.sendSeq++, session.gssMechTypes, session.gssAccSubkey); creds = gss::buildSpnegoResp(gss::ACCEPT_COMPLETED, &krb5oid, krb5reply, mic); /* GSS-SPNEGO has no RFC 4752 layer negotiation: the bind is * done, and the client signs or seals the following PDUs as Loading @@ -1568,7 +1570,8 @@ std::vector<uint8_t> ActiveDirectory::handleBindRequest(const uint8_t *content, * with a max receive buffer. Wrapped (sign) with the context key. */ uint32_t maxBuf = 0x000FFFFF; std::vector<uint8_t> sec = {0x07, uint8_t(maxBuf >> 16), uint8_t(maxBuf >> 8), uint8_t(maxBuf)}; auto tok = gss::wrap(session.gssKey, session.gssEtype, true, session.sendSeq++, sec); auto tok = gss::wrap(session.gssKey, session.gssEtype, true, session.sendSeq++, sec, false, session.gssAccSubkey); session.gssState = LdapSession::GssSentSecLayer; return bindResp(SASL_BIND_IN_PROGRESS, &tok); } Loading
plugin/ad/ad.h +1 −0 Changes for plugin/ad/ad.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -228,6 +228,7 @@ namespace fenrirds { int ssf = 0; uint64_t sendSeq = 0; /* acceptor -> client */ uint64_t recvSeq = 0; /* client -> acceptor */ bool gssAccSubkey = false; /* context key = our AP-REP subkey */ }; /*************************************************************************** Loading
plugin/krb5/krb5.cpp +21 −3 Changes for plugin/krb5/krb5.cpp: 21 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -3882,6 +3882,20 @@ bool Krb5KDC::gssAccept(const std::vector<uint8_t> &apReqData, GssAcceptResult & out.acceptorSeq = variant == 0 ? (Krb5Crypto::randomNonce() & 0x3fffffff) : 0; if (ap.ap_options & 0x20000000) { Krb5Service svc("", "", ap.ticket.sname.realm, svcKey); /* Like Windows and Heimdal acceptors, assert our own subkey for AES * contexts: it becomes the GSS context key (MIC, wrap, the SMB * session key); our tokens then carry the AcceptorSubkey flag. */ Krb5SessionKey accKey; int accEtype = auth.has_subkey ? auth.subkey.enctype : et.session_key.enctype; bool useAccKey = variant == 0 && (accEtype == KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1 || accEtype == KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1); if (useAccKey) { accKey.enctype = static_cast<Krb5EncType>(accEtype); accKey.keydata = Krb5Crypto::randomBytes(accEtype == KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1 ? 32 : 16); out.sessionKey = accKey.keydata; out.sessionEtype = accEtype; out.acceptorSubkey = true; } if (variant == 3) { auto legacy = Asn1Der::encodePaEncTimestamp(auth.ctime, auth.cusec); Krb5ApRep ap_rep; Loading @@ -3892,13 +3906,14 @@ bool Krb5KDC::gssAccept(const std::vector<uint8_t> &apReqData, GssAcceptResult & ap_rep.enc_part = Krb5Crypto::encrypt(et.session_key.keydata, legacy, KRB5_KU_AP_REP_ENC_PART); out.apRep = ap_rep.serialize(); } else { out.apRep = svc.buildApRep(auth, et.session_key, out.acceptorSeq); out.apRep = svc.buildApRep(auth, et.session_key, out.acceptorSeq, useAccKey ? &accKey : nullptr); } } out.gssFlags = auth.has_gss_cksum ? auth.gss_flags : 0; out.initiatorSeq = auth.seq_number; std::cerr << "[KDC] gssAccept " << out.clientPrincipal << " variant=" << "ABCD"[out.apRepVariant] << " subkey=" << auth.has_subkey << " subkey=" << auth.has_subkey << " accSubkey=" << out.acceptorSubkey << " flags=0x" << std::hex << out.gssFlags << " initSeq=0x" << out.initiatorSeq << " accSeq=0x" << out.acceptorSeq << std::dec << " mutual=" << !out.apRep.empty() << std::endl; return true; Loading Loading @@ -4435,7 +4450,8 @@ bool Krb5Service::verifyApReq(const std::vector<uint8_t> &apReqData, std::vector<uint8_t> Krb5Service::buildApRep(const Krb5Authenticator &auth, const Krb5SessionKey &sessionKey, uint32_t seqNumber) { uint32_t seqNumber, const Krb5SessionKey *subkey) { /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE { * ctime [0] KerberosTime, cusec [1] Microseconds, * subkey [2] EncryptionKey OPTIONAL, seq-number [3] UInt32 OPTIONAL } Loading @@ -4446,6 +4462,8 @@ std::vector<uint8_t> Krb5Service::buildApRep(const Krb5Authenticator &auth, std::vector<uint8_t> seq; Asn1Der::encodeContextTag(seq, 0, Asn1Der::encodeGeneralizedTime(auth.ctime)); Asn1Der::encodeContextTag(seq, 1, Asn1Der::encodeUInteger(auth.cusec)); if (subkey && !subkey->keydata.empty()) Asn1Der::encodeContextTag(seq, 2, Asn1Der::encodeEncryptionKey(*subkey)); Asn1Der::encodeContextTag(seq, 3, Asn1Der::encodeUInteger(seqNumber & 0x7fffffff)); std::vector<uint8_t> repData; Asn1Der::encodeTLV(repData, 0x7B /* [APPLICATION 27] */, Asn1Der::encodeSequence(seq)); Loading
plugin/krb5/krb5.h +2 −1 Changes for plugin/krb5/krb5.h: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -927,7 +927,8 @@ namespace fenrirds { /* Build an AP-REP response */ std::vector<uint8_t> buildApRep(const Krb5Authenticator &auth, const Krb5SessionKey &sessionKey, uint32_t seqNumber = 0); uint32_t seqNumber = 0, const Krb5SessionKey *subkey = nullptr); private: Krb5Principal _ServicePrincipal; Loading
plugin/smb/smb.cpp +2 −1 Changes for plugin/smb/smb.cpp: 2 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -753,7 +753,8 @@ SmbServer::Reply SmbServer::sessionSetup(Conn &c, const smb::Smb2Header &req, std::vector<uint8_t> outTok; if (spnego) { std::vector<uint8_t> oid = gss::firstMechOid(mechTypes); auto m = gss::getMic(res.sessionKey, res.sessionEtype, true, res.acceptorSeq, mechTypes); auto m = gss::getMic(res.sessionKey, res.sessionEtype, true, res.acceptorSeq, mechTypes, res.acceptorSubkey); outTok = gss::buildSpnegoResp(gss::ACCEPT_COMPLETED, &oid, krb5reply, m); } else { outTok = krb5reply; Loading