Is it bad practice to have executable code in my channel state object?
I agree that you should pull this functionality out of CommunicationStateMachine. Your state machine should only expose the methods necessarily to make changes in state and to query the current state. Your CommunicationStateMachine class should also be responsible for enforcing the rules of your state machine, i.e. ensuring that only valid state transitions happen. This logic is typically hidden inside the class and invoked when an attempt is made to change state.

In general, the approach you've suggested (the State design pattern) seems like a sensible choice based on your description of your requirements.

Minor note: you've got a small typo on checkJsonMessageIntegraty, which should be Integrity at the end. It may also be more intuitive if your class is called JsonProcessor to reflect its purpose.