krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context, const krb5_data *inbuf, krb5_kvno *kvno, krb5_enctype *enctype) { krb5_error_code ret; #ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */ { krb5_ap_req ap_req; ret = krb5_decode_ap_req(context, inbuf, &ap_req); if (ret) return ret; *kvno = get_kvno_from_ap_req(&ap_req); *enctype = get_enctype_from_ap_req(&ap_req); smb_krb5_free_ap_req(context, &ap_req); } #elif defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */ { krb5_ap_req *ap_req = NULL; ret = decode_krb5_ap_req(inbuf, &ap_req); if (ret) return ret; *kvno = get_kvno_from_ap_req(ap_req); *enctype = get_enctype_from_ap_req(ap_req); smb_krb5_free_ap_req(context, ap_req); } #else #error UNKOWN_KRB5_AP_REQ_DECODING_FUNCTION #endif return ret; }
void DecryptionManager::PacketHandler::parseFirstMessage(Packet* packet) { // Parse input token from thrift request. unique_ptr<IOBuf> msg = removeThriftHeader(packet); if (!msg) { return; } apache::thrift::sasl::SaslStart saslStart; apache::thrift::sasl::SaslAuthService_authFirstRequest_pargs pargs; pargs.saslStart = &saslStart; try { std::string methodName; try { methodName = PargsPresultProtoDeserialize( header_->getProtocolId(), pargs, msg.get(), T_CALL).first; } catch (const TProtocolException& e) { if (header_->getProtocolId() == protocol::T_BINARY_PROTOCOL && e.getType() == TProtocolException::BAD_VERSION) { methodName = PargsPresultProtoDeserialize( protocol::T_COMPACT_PROTOCOL, pargs, msg.get(), T_CALL).first; } else { onError("Protocol mismatch parsing first thrift security message"); return; } } if (methodName != "authFirstRequest") { onError("Bad first auth request. Maybe not secure thrift connection?"); return; } } catch(...) { onError("Caught exception parsing first thrift security message"); } std::string authReq = saslStart.request.response; // Parse encrypted authenticator from input token. This is mostly // copied from accept_sec_context.c. gss_buffer_desc inputToken; inputToken.length = authReq.length(); inputToken.value = (void*)authReq.data(); krb5_data ap_req; krb5_error_code code; unsigned char *ptr; char *sptr; krb5_ap_req *request = nullptr; ptr = (unsigned char*) inputToken.value; code = gssint_g_verify_token_header(gss_mech_krb5, // always use krb5 &(ap_req.length), &ptr, KG_TOK_CTX_AP_REQ, inputToken.length, 1); if (code) { onError("Failed to verify ap_req input token header"); return; } sptr = (char*) ptr; TREAD_STR(sptr, ap_req.data, ap_req.length); code = decode_krb5_ap_req(&ap_req, &request); if (code) { onError("Cannot decode ap_req"); return; } readServiceSessionKey(request->ticket); if (!sessionKey_ || sessionKey_->length == 0) { onError("Failed to read session key"); return; } krb5_data scratch; scratch.length = request->authenticator.ciphertext.length; scratch.data = (char*)malloc(scratch.length); if (!scratch.data) { throw std::runtime_error("Cannot allocate memory"); } SCOPE_EXIT { memset(scratch.data, 0, scratch.length); free(scratch.data); }; code = krb5_c_decrypt(ctx_->get(), sessionKey_, KRB5_KEYUSAGE_AP_REQ_AUTH, 0, &request->authenticator, &scratch); if (code) { onError("Cannot decrypt authenticator"); return; } krb5_authenticator *authenticator; code = decode_krb5_authenticator(&scratch, &authenticator); if (code) { onError("Cannot decode authenticator"); return; } SCOPE_EXIT { free(authenticator); }; // Store this subsession key. In the current thrift security // implementation this subkey is always present and server // uses it to generate another subkey, which will be used for // encrypt/decrypt application messages. if (authenticator->subkey) { krb5_copy_keyblock(ctx_->get(), authenticator->subkey, &subkey_); } }