Beispiel #1
0
static krb5_error_code
decrypt_authenticator(krb5_context context, const krb5_ap_req *request,
		      krb5_authenticator **authpp, int is_ap_req)
{
    krb5_authenticator *local_auth;
    krb5_error_code retval;
    krb5_data scratch;
    krb5_keyblock *sesskey;

    sesskey = request->ticket->enc_part2->session;

    scratch.length = request->authenticator.ciphertext.length;
    if (!(scratch.data = malloc(scratch.length)))
	return(ENOMEM);

    if ((retval = krb5_c_decrypt(context, sesskey,
				 is_ap_req?KRB5_KEYUSAGE_AP_REQ_AUTH:
				 KRB5_KEYUSAGE_TGS_REQ_AUTH, 0,
				 &request->authenticator, &scratch))) {
	free(scratch.data);
	return(retval);
    }

#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
free(scratch.data);}

    /*  now decode the decrypted stuff */
    if (!(retval = decode_krb5_authenticator(&scratch, &local_auth))) {
	*authpp = local_auth;
    }
    clean_scratch();
    return retval;
}
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_);
  }
}